#include "stdafx.h"
#include "R09InstructionSet.h"

R09InstructionSet::R09InstructionSet(void)
{
	
}

void R09InstructionSet::Add()
{
	registers[SAVEREG] = (Int32)registers[REG1] + (Int32)registers[REG2];
}

void R09InstructionSet::Addl()
{
	registers[SAVEREG] = (Int32)registers[REG1] + (Int32)(LITERAL);
}

void R09InstructionSet::Sub()
{
	registers[SAVEREG] = (Int32)registers[REG1] - (Int32)registers[REG2];
}

void R09InstructionSet::Subl()
{
	registers[SAVEREG] = (Int32)registers[REG1] - (LITERAL);
}

void R09InstructionSet::Mul()
{
	UInt64 value = (Int32)registers[REG1] * (Int32)registers[REG2];
	LO = (value << 32) >> 32;
	HI = value >> 32;
}

void R09InstructionSet::Div()
{
	LO = (Int32)registers[REG1] / (Int32)registers[REG2];
	HI = (Int32)registers[REG1] % (Int32)registers[REG2];
}

void R09InstructionSet::Lddw()
{
	registers[SAVEREG] = ram[ADDRESS];
}

void R09InstructionSet::Ldw()
{
	registers[SAVEREG] = (ram[ADDRESS] << 16) >> 16;
}

void R09InstructionSet::Ldb()
{
	registers[SAVEREG] = (ram[ADDRESS] << 24) >> 24;
}

void R09InstructionSet::Ldl()
{
	registers[SAVEREG] = LITERAL;
}

void R09InstructionSet::Stdw()
{
	ram[ADDRESS] = registers[SAVEREG];
}

void R09InstructionSet::Stb()
{

}

void R09InstructionSet::Mfh()
{
	registers[SAVEREG] = HI;
}

void R09InstructionSet::Mfl()
{
	registers[SAVEREG] = LO;
}

void R09InstructionSet::And()
{
	registers[SAVEREG] = registers[REG1] & registers[REG2];
}

void R09InstructionSet::Andl()
{
	registers[SAVEREG] = registers[REG1] & LITERAL;
}

void R09InstructionSet::Or()
{
	registers[SAVEREG] = registers[REG1] | registers[REG2];
}

void R09InstructionSet::Orl()
{
	registers[SAVEREG] = registers[REG1] | LITERAL;
}

void R09InstructionSet::Xor()
{
	registers[SAVEREG] = registers[REG1] ^ registers[REG2];
}

void R09InstructionSet::Nor()
{
	registers[SAVEREG] = ~(registers[REG1] | registers[REG2]);
}

void R09InstructionSet::Not()
{
	registers[SAVEREG] = ~registers[REG1];
}

void R09InstructionSet::Slt()
{
	registers[SAVEREG] = ((Int32)registers[REG1] < (Int32)registers[REG2]) ? 1 : 0;
}

void R09InstructionSet::Sltl()
{
	registers[SAVEREG] = ((Int32)registers[REG1] < (Int32)LITERAL) ? 1 : 0;
}

void R09InstructionSet::Sl()
{
	registers[SAVEREG] = registers[REG1] << registers[REG2];
}

void R09InstructionSet::Sr()
{
	registers[SAVEREG] = registers[REG1] >> registers[REG2];
}

void R09InstructionSet::Beq()
{
	if (registers[REG1] == registers[REG2])
	{
		Branch();
	}
}

void R09InstructionSet::Bne()
{
	if (registers[REG1] != registers[REG2])
	{
		Branch();
	}
}

void R09InstructionSet::Bgt()
{
	if (registers[REG1] > registers[REG2])
	{
		Branch();
	}
}

void R09InstructionSet::Blt()
{
	if (registers[REG1] < registers[REG2])
	{
		Branch();
	}
}

void R09InstructionSet::Bge()
{
	if (registers[REG1] >= registers[REG2])
	{
		Branch();
	}
}

void R09InstructionSet::Ble()
{
	if (registers[REG1] <= registers[REG2])
	{
		Branch();
	}
}

void R09InstructionSet::Branch()
{
#define REGSAVED 13

	// Save registers onto the stack
	callStack[SP++] = PC + 4;
	callStack[SP++] = MAR;
	callStack[SP++] = MDR;
	callStack[SP++] = SP;
	callStack[SP++] = RA;
	callStack[SP++] = FP;
	callStack[SP++] = HI;
	callStack[SP++] = LO;
	callStack[SP++] = F;
	callStack[SP++] = AG;
	callStack[SP++] = BG;
	callStack[SP++] = CG;
	callStack[SP++] = DG;

	// Set FP
	FP = SP - REGSAVED - 1;
	
	// Jump
	JALR
}

void R09InstructionSet::Jmp()
{
	PC = ADDRESS;
}

void R09InstructionSet::Jmpr()
{
	PC = registers[SAVEREG];
}

void R09InstructionSet::Jal()
{
	RA = PC + 4;
	JMP
}

void R09InstructionSet::Jalr()
{
	RA = PC + 4;
	JMPR
}

void R09InstructionSet::Ret()
{
	// Clear locals from the stack
	SP = FP + REGSAVED + 1;

	// Reset registers
	DG = callStack[--SP];
	CG = callStack[--SP];
	BG = callStack[--SP];
	AG = callStack[--SP];
	F = callStack[--SP];
	LO = callStack[--SP];
	HI = callStack[--SP];
	FP = callStack[--SP];
	RA = callStack[--SP];
	SP = callStack[--SP];
	MDR = callStack[--SP];
	MAR = callStack[--SP];
	PC = callStack[--SP];

	// Put the return address onto the stack
	PUSH
}

void R09InstructionSet::Mov()
{
	registers[SAVEREG] = registers[REG1];
}

void R09InstructionSet::Clr()
{
	registers[SAVEREG] = Z;
}

void R09InstructionSet::Push()
{
	callStack[SP++] = REG1;
}

void R09InstructionSet::Pop()
{
	registers[SAVEREG] = callStack[--SP];
}
